
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.*;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;


public class CentralServerT implements Runnable{

    private Socket client;
    private ConcurrentHashMap<Integer, Address> storagePointer;
    private ConcurrentHashMap<Address,Integer> numberOfKeys;
    private transient ObjectInputStream in;
    private transient ObjectOutputStream out;


    public CentralServerT(Socket client, ConcurrentHashMap<Integer, Address> storagePointer, ConcurrentHashMap<Address, Integer> numberOfKeys) {
        this.client = client;
        this.storagePointer = storagePointer;
        this.numberOfKeys = numberOfKeys;
        try {
            this.out = new ObjectOutputStream(client.getOutputStream());
            //this.out.flush();            
            this.in = new ObjectInputStream(client.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void run(){
        Request req;
        Address addr;
        boolean exit = false;
        while(!exit){ //modificar condicao
            req = null;
            addr = null;
            try {
                Object obj = in.readObject();

                if(obj instanceof Request){
                    req = (Request)obj;

                    if(req.getOp().equals("get") || req.getOp().equals("put")){
                        Address temp = null;
                        HashMap<Address,HashMap<Integer, byte[]>> addresses= new HashMap<Address,HashMap<Integer,byte[]>>();
                        for(int key: req.getData().keySet()){
                            if(req.getOp().equals("get")){
                                temp = StoredIn(key);
                            }else{
                                temp=StoredIn(key);
                                if(temp == null){
                                    temp = getLessFilled();
                                }
                            }
                            if(temp!=null){
                                if(addresses.containsKey(temp)){
                                    addresses.get(temp).put(key,req.getData().get(key));
                                }else{
                                    addresses.put(temp.clone(),new HashMap<Integer, byte[]>());

                                }
                            }
                        }
                        Request[] requests = new Request[addresses.keySet().size()];
                        int i=0;
                        for(Address ad : addresses.keySet()){
                            requests[i]=new Request(addresses.get(ad),ad,req.getOp());
                            i++;
                        }
                        System.out.println("adresses tem tamanho "+addresses.keySet().size());
                        out.writeObject(requests);

                    }
                }else if(obj instanceof Address){
                    Address aux = (Address)obj;
                    numberOfKeys.put(aux,0);
                    System.out.println(storagePointer.keySet().toString());
                }



            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } catch (ClassNotFoundException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }finally {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                exit=true;
            }

        }



    }



    //Returns the address of the server with less keys
    public Address getLessFilled(){
        Address ad = null;
        int keys = Integer.MAX_VALUE;



        for(Address a : numberOfKeys.keySet()){
            if(numberOfKeys.get(a) < keys){
                ad = a;
            }
        }
        return ad;
    }

    public Address StoredIn(int key){
        return storagePointer.get(key);
    }



}


